package com.newshub.common.fetch;

import com.newshub.admin.entity.RssFeed;
import com.newshub.admin.entity.RssFetchLog;
import com.newshub.business.entity.News;
import com.newshub.business.entity.Source;
import com.newshub.business.entity.Category;
import com.newshub.admin.mapper.RssFeedMapper;
import com.newshub.admin.mapper.RssFetchLogMapper;
import com.newshub.business.mapper.NewsMapper;
import com.newshub.admin.service.RssParseService;
import com.newshub.business.service.SourceService;
import com.newshub.business.service.CategoryService;
import com.newshub.common.util.ContentCleaner;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.List;

/**
 * RSS抓取任务实现
 * 负责RSS源的抓取、解析、清洗和存储
 */
@Slf4j
@Component
public class RssFetchTask implements FetchTask {
    
    @Autowired
    private RssParseService rssParseService;
    
    @Autowired
    private RssFeedMapper rssFeedMapper;
    
    @Autowired
    private RssFetchLogMapper rssFetchLogMapper;
    
    @Autowired
    private NewsMapper newsMapper;
    
    @Autowired
    private SourceService sourceService;
    
    @Autowired
    private CategoryService categoryService;
    
    @Autowired
    private ContentCleaner contentCleaner;
    
    @Override
    public FetchResult execute(Long feedId) {
        Integer feedIdInt = feedId.intValue();
        LocalDateTime startTime = LocalDateTime.now();
        LocalDateTime endTime = null;
        
        try {
            log.info("开始执行RSS抓取任务，feedId: {}", feedId);
            
            // 1. 获取RSS源配置
            RssFeed rssFeed = rssFeedMapper.selectById(feedIdInt);
            if (rssFeed == null) {
                throw new RuntimeException("RSS源不存在: " + feedId);
            }
            
            if (rssFeed.getStatus() != 1) {
                throw new RuntimeException("RSS源已禁用: " + rssFeed.getName());
            }
            
            // 2. 解析RSS（获取HTTP状态码与响应大小）
            RssParseResult parseResult = rssParseService.parseRssFeed(rssFeed);
            List<FetchedNews> fetchedNewsList = parseResult.getEntries();
            Integer httpStatusCode = parseResult.getHttpStatusCode();
            Long responseSize = parseResult.getResponseSize();
            log.info("RSS解析完成，获取到 {} 条新闻，HTTP={}，size={}", 
                    fetchedNewsList != null ? fetchedNewsList.size() : 0, httpStatusCode, responseSize);
            
            // 3. 数据清洗和去重
            List<FetchedNews> cleanedNewsList = cleanAndDeduplicate(fetchedNewsList, rssFeed);
            log.info("数据清洗完成，去重后剩余 {} 条新闻", cleanedNewsList.size());
            
            // 4. 保存到数据库
            SaveStats saveStats = saveNewsToDatabase(cleanedNewsList, rssFeed);
            int savedCount = saveStats.savedCount;
            log.info("新闻保存完成，成功保存 {} 条（重复 {} 条）", savedCount, saveStats.duplicateCount);
            
            // 5. 更新RSS源状态
            updateRssFeedStatus(rssFeed, true, null);
            
            endTime = LocalDateTime.now();
            FetchResult result = FetchResult.success(savedCount, startTime, endTime);
            result.setFetchedNews(cleanedNewsList);
            result.setDuplicateCount(saveStats.duplicateCount);
            result.setTotalFetched(fetchedNewsList != null ? fetchedNewsList.size() : 0);
            result.setCleanedCount(cleanedNewsList.size());
            result.setSavedCount(savedCount);
            // 修正：newsCount应该表示总抓取数，而不是保存数
            result.setNewsCount(fetchedNewsList != null ? fetchedNewsList.size() : 0);
            // 使用实际HTTP状态码和响应大小
            result.setHttpStatusCode(httpStatusCode);
            result.setResponseSize(responseSize);
            
            // 6. 严格标准下设置status：HTTP 200 且 totalFetched>0 才算成功（不依赖保存数）
            boolean strictSuccess = (result.getHttpStatusCode() != null && result.getHttpStatusCode() == 200)
                    && (result.getTotalFetched() > 0);
            result.setSuccess(strictSuccess);

            // 7. 记录抓取日志
            saveFetchLog(rssFeed, result);
            
            log.info("RSS抓取任务执行完成，feedId: {}, 保存新闻数: {}", feedId, savedCount);
            return result;
            
        } catch (Exception e) {
            endTime = LocalDateTime.now();
            log.error("RSS抓取任务执行失败，feedId: {} - {}", feedId, e.getMessage(), e);
            
            // 更新RSS源错误状态
            try {
                RssFeed rssFeed = rssFeedMapper.selectById(feedIdInt);
                if (rssFeed != null) {
                    updateRssFeedStatus(rssFeed, false, e.getMessage());
                }
            } catch (Exception updateException) {
                log.error("更新RSS源状态失败: {}", updateException.getMessage());
            }
            
            FetchResult result = FetchResult.failure(e.getMessage(), startTime, endTime);
            
            // 记录错误日志
            try {
                RssFeed rssFeed = rssFeedMapper.selectById(feedIdInt);
                if (rssFeed != null) {
                    saveFetchLog(rssFeed, result);
                }
            } catch (Exception logException) {
                log.error("记录错误日志失败: {}", logException.getMessage());
            }
            
            return result;
        }
    }
    
    @Override
    public String getTaskType() {
        return "RSS";
    }
    
    /**
     * 数据清洗和去重
     */
    private List<FetchedNews> cleanAndDeduplicate(List<FetchedNews> newsList, RssFeed rssFeed) {
        return newsList.stream()
                .map(this::cleanNewsContent)
                .filter(news -> news.getTitle() != null && !news.getTitle().trim().isEmpty())
                .filter(news -> news.getUrl() != null && !news.getUrl().trim().isEmpty())
                .toList();
    }
    
    /**
     * 清洗新闻内容
     */
    private FetchedNews cleanNewsContent(FetchedNews news) {
        try {
            // 清洗标题
            if (news.getTitle() != null) {
                news.setTitle(contentCleaner.cleanTitle(news.getTitle()));
            }
            
            // 清洗摘要
            if (news.getSummary() != null) {
                news.setSummary(contentCleaner.cleanSummary(news.getSummary()));
            }
            
            // 清洗正文内容
            if (news.getContent() != null) {
                news.setContent(contentCleaner.cleanHtmlContent(news.getContent()));
            }
            
        } catch (Exception e) {
            log.warn("清洗新闻内容失败: {} - {}", news.getTitle(), e.getMessage());
        }
        
        return news;
    }
    
    /**
     * 保存新闻到数据库
     */
    private SaveStats saveNewsToDatabase(List<FetchedNews> newsList, RssFeed rssFeed) {
        int savedCount = 0;
        int duplicateCount = 0;
        LocalDateTime now = LocalDateTime.now();
        
        // 批量获取分类和信源信息，避免循环查询
        Category category = null;
        Source source = null;
        
        if (rssFeed.getCategoryId() != null) {
            try {
                category = categoryService.getCategoryById(rssFeed.getCategoryId());
            } catch (Exception e) {
                log.warn("获取分类信息失败: categoryId={}, error={}", 
                        rssFeed.getCategoryId(), e.getMessage());
            }
        }
        
        if (rssFeed.getSourceId() != null) {
            try {
                source = sourceService.getSourceById(rssFeed.getSourceId());
            } catch (Exception e) {
                log.warn("获取信源信息失败: sourceId={}, error={}", 
                        rssFeed.getSourceId(), e.getMessage());
            }
        }
        
        for (FetchedNews fetchedNews : newsList) {
            try {
                // 1. 检查externalId是否已存在（去重）
                if (fetchedNews.getExternalId() != null) {
                    News existingNews = newsMapper.selectByExternalId(fetchedNews.getExternalId());
                    if (existingNews != null) {
                        duplicateCount++;
                        log.debug("新闻已存在，跳过: {}", fetchedNews.getTitle());
                        continue;
                    }
                }
                
                // 2. 映射字段到News实体
                News news = new News();
                news.setTitle(fetchedNews.getTitle());
                news.setSummary(fetchedNews.getSummary());
                news.setContent(fetchedNews.getContent());
                news.setUrl(fetchedNews.getUrl());
                news.setImageUrl(fetchedNews.getImageUrl());
                news.setAuthor(fetchedNews.getAuthor());
                news.setPublishTime(fetchedNews.getPublishTime());
                
                // 设置RSS相关字段
                news.setSourceType("rss");
                news.setSourceFeedId(rssFeed.getId().longValue());
                news.setExternalId(fetchedNews.getExternalId());
                news.setFetchTime(now);
                
                // 设置分类和来源信息（从RSS源配置中获取）
                news.setCategoryId(rssFeed.getCategoryId());
                news.setSourceId(rssFeed.getSourceId());
                
                // 设置分类名称和来源名称（使用批量查询的结果）
                if (category != null) {
                    news.setCategoryName(category.getName());
                }
                
                if (source != null) {
                    news.setSourceName(source.getName());
                }
                
                // 通过信源获取地域信息
                if (source != null && source.getRegionId() != null) {
                    log.debug("获取到信源地域信息: sourceId={}, regionId={}", 
                            rssFeed.getSourceId(), source.getRegionId());
                }
                
                // 设置默认值
                news.setStatus(1); // 正常状态
                news.setViewCount(0);
                news.setIsHot(0);
                news.setWordCount(calculateWordCount(fetchedNews.getContent()));
                news.setCreatedAt(now);
                news.setUpdatedAt(now);
                
                // 3. 插入数据库
                int result = newsMapper.insert(news);
                if (result > 0) {
                    savedCount++;
                    log.debug("成功保存新闻: {}", news.getTitle());
                }
                
            } catch (Exception e) {
                log.error("保存新闻失败: {} - {}", fetchedNews.getTitle(), e.getMessage());
            }
        }
        
        log.info("新闻保存完成，成功保存 {} 条，总计 {} 条，重复 {} 条", savedCount, newsList.size(), duplicateCount);
        return new SaveStats(savedCount, duplicateCount);
    }

    private static class SaveStats {
        final int savedCount;
        final int duplicateCount;
        SaveStats(int savedCount, int duplicateCount) {
            this.savedCount = savedCount;
            this.duplicateCount = duplicateCount;
        }
    }
    
    /**
     * 计算字数
     */
    private Integer calculateWordCount(String content) {
        if (content == null || content.trim().isEmpty()) {
            return 0;
        }
        // 简单的中文字符计数
        return content.replaceAll("\\s+", "").length();
    }
    
    /**
     * 更新RSS源状态
     */
    private void updateRssFeedStatus(RssFeed rssFeed, boolean success, String errorMessage) {
        try {
            rssFeed.setLastFetchAt(LocalDateTime.now());
            rssFeed.setLastFetchDate(LocalDate.now());
            
            // 处理 fetchCount 的 null 值情况
            Integer currentFetchCount = rssFeed.getFetchCount();
            rssFeed.setFetchCount((currentFetchCount != null ? currentFetchCount : 0) + 1);
            
            if (success) {
                rssFeed.setErrorCount(0);
                rssFeed.setLastErrorAt(null);
            } else {
                // 处理 errorCount 的 null 值情况
                Integer currentErrorCount = rssFeed.getErrorCount();
                rssFeed.setErrorCount((currentErrorCount != null ? currentErrorCount : 0) + 1);
                rssFeed.setLastErrorAt(LocalDateTime.now());
            }
            
            rssFeedMapper.update(rssFeed);
            log.info("RSS源状态更新完成: {}, fetchCount: {}, errorCount: {}", 
                    rssFeed.getName(), rssFeed.getFetchCount(), rssFeed.getErrorCount());
            
        } catch (Exception e) {
            log.error("更新RSS源状态失败: {} - {}", rssFeed.getName(), e.getMessage());
        }
    }
    
    /**
     * 保存抓取日志
     */
    private void saveFetchLog(RssFeed rssFeed, FetchResult result) {
        try {
            RssFetchLog fetchLog = RssFetchLog.builder()
                    .rssFeedId(rssFeed.getId().longValue())
                    .fetchDate(LocalDate.now())
                    .fetchTime(LocalDateTime.now())
                    .status(result.isSuccess() ? "success" : "failed")
                    .newsCount(result.getNewsCount())
                    .duplicateCount(result.getDuplicateCount())
                    .totalFetched(result.getTotalFetched())
                    .cleanedCount(result.getCleanedCount())
                    .savedCount(result.getSavedCount())
                    .httpStatusCode(result.getHttpStatusCode())
                    .responseSize(result.getResponseSize())
                    .errorMessage(result.getErrorMessage())
                    .executionTime(result.getExecutionTime())
                    .createdAt(LocalDateTime.now())
                    .build();
            
            rssFetchLogMapper.insert(fetchLog);
            
        } catch (Exception e) {
            log.error("保存抓取日志失败: {} - {}", rssFeed.getName(), e.getMessage());
        }
    }
}
